package com.bitcointoolkit.web.service.tx;

import com.bitcointoolkit.common.cash.BechCashUtil;
import com.bitcointoolkit.common.cash.EncodeUtil;
import com.bitcointoolkit.common.cash.PubKey;

import java.util.ArrayList;
import java.util.List;

/**
 * 输出脚本
 *
 * @author caican
 * @date 18/6/17
 */
public class TxScriptPubkey extends TxScript {

    private final static BechCashUtil CASH = BechCashUtil.getInstance();

    private List<String> addresses;

    private String type;

    private int reqSigs;// TODO

    public TxScriptPubkey(String scriptHex) {
        super(scriptHex);
        if (txType != TxType.TX_NULL_DATA) {
            extractDestination();
        }
        this.type = txType.toString();
    }

    private void extractDestination() {
        addresses = new ArrayList<>();
        switch (txType) {
            case TX_PUBKEYHASH:
                int[] pubkeyhash = EncodeUtil.subInt(hex, 3, 23);
                byte[] pubkeyb = new byte[20];
                for (int i=0;i<pubkeyb.length; i++) {
                    pubkeyb[i] = (byte) pubkeyhash[i];
                }
                addresses.add(CASH.pubKeyHashToLegacy(pubkeyb));
                break;
            case TX_MULTISIG:
                int count = hex[hex.length-2] - 0x50;// pubkey 个数
                for (int i=0;i<count;i++) {
                    int startIdx = 1 + i*34 +1;
                    int[] pubkey = EncodeUtil.subInt(hex, startIdx, startIdx +33);
                    byte[] tmp = new byte[pubkey.length];
                    for (int j=0;j<tmp.length; j++) {
                        tmp[j] = (byte) pubkey[j];
                    }
                    PubKey key = new PubKey(tmp);
                    addresses.add(key.getAddress(true));
                }
                break;
            case TX_SCRIPTHASH:
                int[] scripthash = EncodeUtil.subInt(hex, 2, 22);
                byte[] tmpscript = new byte[20];
                for (int i=0;i<tmpscript.length; i++) {
                    tmpscript[i] = (byte) scripthash[i];
                }
                addresses.add(CASH.scriptHashToLegacy(tmpscript));
                break;
            case TX_NULL_DATA:
            case TX_PUBKEY:
            default:
                throw new RuntimeException("不支持的类型:" + txType);
        }

//        standard.cpp ExtractDestination
//        if (whichType == TX_PUBKEY) {
//            CPubKey pubKey(vSolutions[0]);
//            if (!pubKey.IsValid()) {
//                return false;
//            }
//
//            addressRet = pubKey.GetID();
//            return true;
//        }
//        if (whichType == TX_PUBKEYHASH) {
//            addressRet = CKeyID(uint160(vSolutions[0]));
//            return true;
//        }
//        if (whichType == TX_SCRIPTHASH) {
//            addressRet = CScriptID(uint160(vSolutions[0]));
//            return true;
//        }
    }

    @Override
    protected TxType judgeType() {
        // 参见standard.cpp Solver()
        // 不支持最老的 PUBKEY 方式(P2Pk)
        if(hex.length == 25 && hex[0] == OpCodeType.OP_DUP.getCode()
                && hex[1] == OpCodeType.OP_HASH160.getCode()
                && hex[2] == 0x14
                && hex[23] == OpCodeType.OP_EQUALVERIFY.getCode()
                && hex[24] == OpCodeType.OP_CHECKSIG.getCode()) {
            // P2PKH
            // OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
            txType = TxType.TX_PUBKEYHASH;
        } else if (hex.length == 23 && hex[0] == OpCodeType.OP_HASH160.getCode()
                && hex[1] == 0x14
                && hex[22] == OpCodeType.OP_EQUAL.getCode()) {
            // P2SH
            // OP_HASH160 [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_EQUAL
            txType = TxType.TX_SCRIPTHASH;
        } else if(hex.length >= 37 && ((hex.length-3) % 34 == 0)
                && hex[0] >= OpCodeType.OP_1.getCode()
                && hex[hex.length-2] >= OpCodeType.OP_1.getCode()
                && hex[hex.length-1] == OpCodeType.OP_CHECKMULTISIG.getCode()) {
            // MUTISIG
            // m {pubkey}...{pubkey} n OP_CHECKMULTISIG
            // m < n; m>0   0<n<=20
            txType = TxType.TX_MULTISIG;
        } else if (hex.length > 0 && hex[0] == OpCodeType.OP_RETURN.getCode()
                && isPushOnly(1)) {
            txType = TxType.TX_NULL_DATA;
        } else {
            txType = TxType.TX_NONSTANDARD;
        }
        return txType;
    }

    public List<String> getAddresses() {
        return addresses;
    }

    public String getType() {
        return type;
    }

    public int getReqSigs() {
        return reqSigs;
    }
}
